/*
 * $Id: GateProc.cc,v 1.9 2007-06-21 10:49:01 baconevi Exp $
 */

#include "Globals.h"
#include "GateProc.h"
#include "Command.h"
#include <xp/bas/stdlib.h>
#include <xp/bas/assert.h>
#include <xpp/bas/MutexLock.h>

GateProc::GateProc (
	const xp_char_t* name, Socket* s, Address* a, Gate* g): 
	Named (name), Sttp ((Transmittable*)s, a), owner(g)
{
	exit_requested = false;

	setMaxRawCmdLen       (10000);
	setMaxArgCount        (20);
	disableReceiveTimeout ();
	disableSendTimeout    ();
	setOptSendNewline     (true);

	{
		MutexLock lock (&app_env_mutex);
		xp_time_t timeout = app_env.gateTimeout();

		if (timeout == -1) disableReceiveTimeout();
		else enableReceiveTimeout (timeout);
	}

	/*
	setSendPasswd ("@!#", 3);
	setRecvPasswd ("@!#", 3);
	*/

	addCmd (CMD_DISCON, (CmdProc)&GateProc::proc_discon);
	//addCmd (CMD_ADMATH, (CmdProc)&GateProc::proc_admath);
	addCmd (CMD_SHTDWN, (CmdProc)&GateProc::proc_shtdwn);
	addCmd (CMD_ENVGET, (CmdProc)&GateProc::proc_envget);
	addCmd (CMD_ENVSET, (CmdProc)&GateProc::proc_envset);
	addCmd (CMD_ENVLST, (CmdProc)&GateProc::proc_envlst);
	addCmd (CMD_LOGLST, (CmdProc)&GateProc::proc_loglst);
	addCmd (CMD_LOGCLR, (CmdProc)&GateProc::proc_logclr);
}

GateProc::~GateProc ()
{
}

int GateProc::preprocess_cmd (const SttpCmd& cmd)
{
	if (XP_LOG_ENABLED(&app_log, XP_LOG_INFO)) 
	{
		String arg_str;
		size_t arg_count = cmd.argCount();

		for (size_t i = 0; i < arg_count; i++) 
		{
			if (i > 0) arg_str.append (XP_T(", "));
			arg_str.append (cmd.argAt(i));
		}

		XP_LOG2 (
			&app_log, name(), XP_LOG_INFO, XP_T("<Q>%s %s"),
			(const xp_char_t*)cmd.name, (const xp_char_t*)arg_str);
	}

	return 0;
}

int GateProc::proc_discon (const SttpCmd& cmd)
{
	PROC_CHECK_ARG_COUNT (cmd, 0);
	exit_requested = true;
	return 0;
}

#if 0
int GateProc::proc_admath (const SttpCmd& cmd)
{
	PROC_CHECK_ARG_COUNT (cmd, 2);

	const xp_char_t* user = cmd.argAt(0);
	const xp_char_t* pass = cmd.argAt(1);

// TODO: load service type from configuration...
	if (xp_authuser(XP_T("system"), user, pass) == -1) {
		SEND_ERR (ERR_AUTH);
		return 0;
	}

//	if (user != getlogin...)

	SEND_CMD_OK;
	return 0;	
}

int GateProc::proc_admpwd (const SttpCmd& cmd)
{
	PROC_CHECK_ARG_COUNT (cmd, 2);

	const xp_char_t* user = cmd.argAt(0);
	const xp_char_t* pass = cmd.argAt(1);

	if (xp_chpasswd(XP_T("passwd"), user, pass) == -1) {
		SEND_ERR (ERR_AUTH);
		return 0;
	}

	SEND_CMD_OK;
	return 0;
}
#endif

int GateProc::proc_shtdwn (const SttpCmd& cmd)
{
	PROC_CHECK_ARG_COUNT (cmd, 1);

	const xp_char_t* ret = cmd.argAt(0);

	if (!xp_stristype(ret,xp_isdigit)) {
		SEND_ERR (ERR_ARG);
		return 0;
	}

	{
		MutexLock lock (&app_main_mutex);
		if (app_main == XP_NULL) {
			SEND_ERR (ERR_GENERAL);
			return 0;
		}
		
		int nret;
		XP_STRTOI (nret, ret, XP_NULL, 10);
		if (app_main->stopWithCode(nret) == -1)  {
			SEND_ERR (ERR_GENERAL);
			return 0;
		}
	}

	SEND_CMD_OK;
	return 0;
}

int GateProc::proc_envget (const SttpCmd& cmd)
{
	PROC_CHECK_ARG_COUNT (cmd, 1);

	const xp_char_t* name = cmd.argAt(0);

/*
	if (!_login.isRootUser()) {
		SEND_ERR (ERR_PERM);
		return 0;
	}
*/

	MutexLock lock (&app_env_mutex);
	const xp_char_t* v;
	if ((v = app_env.itemValueOf (name)) == XP_NULL) {
		SEND_ERR (ERR_FIND);
		return 0;
	}

	SEND_OK (v);
	return 0;
}

int GateProc::proc_envset (const SttpCmd& cmd)
{
	PROC_CHECK_ARG_COUNT (cmd, 2);

	const xp_char_t* name = cmd.argAt(0);
	const xp_char_t* val  = cmd.argAt(1);

/*
	if (!_login.isRootUser()) {
		SEND_ERR (ERR_PERM);
		return 0;
	}
*/

	MutexLock lock (&app_env_mutex);
	if (app_env.setItemValue(name, val) == XP_NULL) {
		SEND_ERR (ERR_SETV);
		return 0;
	}

	const xp_char_t* v = app_env.itemValueOf (name);
	xp_assert (v != XP_NULL);

	if (app_env_path.write (&app_env) == -1) {
		SEND_WARN (ERR_SAVE);
		//return 0;
	}

	SEND_OK (v);
	return 0;
}

int GateProc::proc_envlst (const SttpCmd& cmd)
{
	PROC_CHECK_ARG_COUNT (cmd, 0);

/*
	if (!app_env.getAllowLstCmd() && !_login.isRootUser()) {
		SEND_ERR (ERR_PERM);
		return 0;
	}
*/

	{
		MutexLock lock (&app_env_mutex);
		const AppEnv::ItemList& itemList = app_env.itemList();
		AppEnv::ItemList::Node* np;
		for (np = itemList.head(); np; np = np->forward()) {
			AppEnv::Item& item = np->value;
			xp_char_t* name = app_env.itemName (item.sctn, item.key);
			xp_assert (name != XP_NULL);
			const xp_char_t* val = app_env.itemValueOf (name);
			xp_assert (val != XP_NULL);
			SEND_CMD_2 (CMD_ENVITM, name, val);
		}
	}

	SEND_CMD_OK;
	return 0;
}

int GateProc::proc_loglst (const SttpCmd& cmd)
{
	PROC_CHECK_ARG_COUNT (cmd, 0);

	// WARNING: this program should not change the log target 
	//          at lease while this function is running as there
	//          is no protection in the accees of the log target.
	const xp_char_t* target = app_log.target.file;
	if ((app_log.type & XP_LOG_FILE) == 0 ||
	    target == XP_NULL || target[0] == XP_T('\0')) 
	{
		SEND_CMD_OK;
		return 0;
	}

	xp_sio_t sio;

	if (xp_sio_open (&sio, target, XP_T("r")) == XP_NULL) 
	{
		SEND_ERR (ERR_FILE);
		return 0;
	}
	
	// the size of the buffer below is only a rough guess.
	xp_char_t buf[XP_LOG_MSG_MAX + XP_LOG_IDENT_MAX * 2 + 100];
	xp_ssize_t n;
	while (1) 
	{
		n = xp_sio_gets (&sio, buf, xp_countof(buf) - 1);
		if (n <= 0) break;
		buf[n] = XP_T('\0');

		// don't care if buf contains null characters in it 
		// because it is not supposed to contain them.
		SEND_CMD_1 (CMD_LOGITM, buf);
	}

	xp_sio_close (&sio);
	SEND_CMD_OK;
	return 0;
}

int GateProc::proc_logclr (const SttpCmd& cmd)
{
	PROC_CHECK_ARG_COUNT (cmd, 0);

	if (xp_log_clear(&app_log) == -1) SEND_ERR (ERR_GENERAL);
	else SEND_CMD_OK;
	return 0;
}

const xp_char_t* GateProc::errorStr () const
{
	switch (p_errcode) {
	case ERR_ARGCOUNT:
		return XP_T("wrong number of arguments");
	case ERR_ARG:
		return XP_T("wrong argument");
	case ERR_PERM:
		return XP_T("insufficient permission");
	case ERR_SETV:
		return XP_T("value not set");
	case ERR_SAVE:
		return XP_T("data not saved");
	case ERR_FIND:
		return XP_T("data not found");
	case ERR_FILE:
		return XP_T("file operation error");
	case ERR_SVRDOWN:
		return XP_T("server going down");
	case ERR_GENERAL:
		return XP_T("general operation error");
	default:
		return Sttp::errorStr ();
	}
}

#if 0
int GateProc::get_auth_info ()
{
	MutexLock lock (&app_env_lock);
	app_env.admauthService();
	app_env.admchpwService();
	app_env.admauthRequired();
}
#endif
